//常规指令：
//tsc --init   取消重复校验  会自动生成tsconfig.json配置文件
//tsc --watch  自动编译  ctrl+c退出
//tsc --noEmitOnError   ts错误时不编译成js
//tsc --noEmitOnError --watch 当ts错误时，不会实时编译生成新的js文件

//1、静态类型检查：编译完代码会检查类型是否正确
var message = "abc";
//message(); // 不会识别为函数，不能调用

//2、非异常故障：不仅仅是编译类型，也可以检查类型，甚至是基本的逻辑
var user={
    "stuName":"zhangsan"
}
console.log(user.stuName);
//console.log(user.stuNo); //没有的属性或方法是不被识别的，会报错

var str1 = "abc";
//str1 = str1.touppercase(); //没有的属性或方法是不被识别的，会报错
str1 = str1.toUpperCase();
console.log(str1);

var info = 10>5 ? 'a':'b';
// if(info !== 'a'){
// }else if(info === 'b'){// if范围包含了else if，ts也能识别，报错
// }

//3、优化编译。以后写ts代码，可以不用一步一编译，使用watch自动编译
//            tsc 文件名.ts --watch

//4、控制类型
//(1)显示类型：声明时，手动给变量加类型
//添加类型的语法：变量名:类型
var num:number = 10.5;
//num = 10.5;
//(2)推断类型：没有手动的写明类型，而是通过赋值操作确定变量类型
var num2 = "abc";
//num2 = 123;
//(3)类型断言：根据业务需要，临时认定变量的类型，做逻辑处理。
//var 变量 = 值 as 类型;
//var 变量 = <类型>值
//let str2 = "hello" as string;
//var str2 = <string>"hello";
//只有当数据类型不确定时，才需要断言。 任意类型 / unknown无类型
// var str2 = ("hello" as any) as number;
// var str3;
// str3  as number;
// var result = str2 - 1;
// console.log(result)
var bl1:any; // 违背了ts的类型限制
var bl2:unknown;
// bl1 = "abc";
// bl1 = 123;
// bl2 = "abc";
// bl2 = 123;

//5、降级编译
function showTest(zfc:string, time:Date){
    //var zfc = zfc || 'mrz';
    console.log("zfc" + "," + time );
    //格式字符串(ES新版中才有)
    console.log(`第一个参数是：${zfc} ， 第二个参数是：${time}`);
}
showTest("abc",new Date());

//6、严格模式
//var str:string = undefined;  //非严格模式是不报错的
// var age:number = null; //非严格模式是不报错的
// function show3(zfc:string, time:Date){
//     console.log(`第一个参数是：${zfc} ， 第二个参数是：${time}`);
// }
// show3('a',new Date());  //参数不匹配会报错

//7、ts中常用类型
//   基本类型[undefined、null、number、string、boolean]、数组类型、枚举类型、any类型、函数类型、对象类型{x:1,y:2}、联合类型x|y、类型别名
//基本类型包括：
//数字类型   :number
var b1 :number = 10;
//字符串类型 :string
var b2 :string = "abc";
//布尔类型   :boolean
var b3 :boolean = true;
//null类型   :null
var b4 :null = null;
//undefined类型 :undefined
var b5 :undefined = undefined;

//数组类型包括：
//方式一 --> :类型[]
var b6:string[];
b6 = ['1','2',"3"];
b6[3] = 'aaa';
console.log(b6[3]);

//方式二 --> :Array<类型>
var b7:Array<number>;
b7 = [10,20,30];
b7[3] = 40;
for(var i=0; i<b7.length; i++){
    console.log(b7[i]);
}

//枚举类型：在规定范围内选数据  枚举存储的就是数字，从0开始，后续选项会在前一个选项基础上+1
//enum关键字表示枚举类型
//枚举名：帕斯卡命名法
enum Gender{
    Man,
    Woman,
    WeiZhi
}
console.log(Gender.Man + "  " + Gender.Woman + "  " + Gender.WeiZhi);//默认是输出数字
//想输出文本信息：
//改为对象封装
let sex :{
    Man:number,
    Woman:number,
    WeiZhi:number,
    properties:{
        0:{code:string},
        1:{code:string},
        2:{code:string}
    }
};
sex = {
    Man:0,
    Woman:1,
    WeiZhi:2,
    properties:{
        0:{code:'Man'},
        1:{code:'Woman'},
        2:{code:'WeiZhi'}
    }
}
console.log(sex.properties[Gender.Man].code);

//在枚举中添加对象属性 --> 属性:{}
var per:{perName:string, perSex:Gender, obj1:{0:number} };
per = {
     perName:"zhangsan",
     perSex:Gender.Man, 
     //perTel:'138188188188',
     obj1:{
         0:2
     }
}
console.log(per);

//any类型  任意类型 
let ctx:any; //默认类型 any
ctx = 123;
ctx = 'abc';
ctx = true;
ctx={
    "a":"1"
}
var obj = {//推断
    num:0
}
// obj();
// obj.method();
// obj.str="abc";
// obj = "aaa";
//var n:boolean = obj;
// var dx:{
//     num:number
// }
// dx = obj;

//函数 
//返回结果的类型约束在参数列表之后写
function test(str:string,info:boolean):number{
    //str-10;
    //str.charAt(0)
    // if(info){
    // }
    //info.substring();
    return 0;//"abc";
}
test('1',true);
var b8 = function(str:string):boolean{
    return true;
}
var b9 = b8("");


//对象类型：将参数识别为对象
//参数是obj，obj是对象，有属性x和y
function test2(obj:{x:number,y:number}){
    console.log(obj.x + "   " + obj.y);
}
test2({x:10,y:20});
//参数是对象类型，但是属性不一定传全
//类型格式--> ?:类型   表示数据可以不传递        ?.    ??
//?? 和 || 的意思有点相似，但是又有点区别。
//??相较||比较严谨, 当值为null或undefined时，??和||都会被忽略，但是0，||会忽略 ??不会.
function test3(mc:{first:string, last?:string}){
    console.log(mc.first);
    console.log(mc.last?.toUpperCase());
    console.log(null||"null||");
    console.log(null??"null??"); 
    console.log(undefined||"undefined||");
    console.log(undefined??"undefined??"); 
    console.log(0||"0||");
    console.log(0??"0??"); 
}
//test3({first:"xing"});
test3({first:"xing",last:"ming"});


//联合类型：
//格式：类型1|类型2...
//常用于传参时
function test4(id : number|string|boolean ){
    console.log(id);
    if(typeof(id) == "number"){
         console.log("传的是数字");
    }else if(typeof(id) == "string"){
         console.log("传的是字符串");
    }else if(typeof(id) == "boolean"){
        console.log("传的是布尔");
   }
 }
 test4("aaa");


//类型别名：使用其他类型名称代替指定类型
//语法：type 自定义类型名 = 值; // 赋值就是写规则
type mytype = 1 | 2 | 3 | 'aaa';
let newNum:mytype;
newNum = "aaa";
